/**
 * Program : Lembar Kerja 04, Hierarchical Modelling
 *           Lighting, Shadow, and Texture, Worksheet 4
 * Berkas  : definitions.h
 * ----------------------------------------------
 * Nama Pembuat :
 *  - Andry Luthfi, (0906629044)
 *  - Hadi Saputro, (0906562871)
 *
 * Aplikasi ini mengimplementasikan konsep Objek Hirarkis
 * serta teknik-teknik pencahayaan pada OpenGL. konsep-konsep
 * didapatkan pada mata kuliah Grafika Komputer.
 *
 * berkas ini berisikan variabel dan definisi utama untuk program
 * beserta beberapa fungsi yang digunakan sebagai pengatur utama
 * aturan program, baik internal maupun eksternal. contoh pengaturan
 * eksternal ialah pengaturan Glut.
 *
 * Hak Cipta (c) 2012, Andry Luthfi, Hadi Saputro
 */

#define OBJECT_WIREFRAME true
#define OBJECT_SHADING false

#define VIEW_ALL 6
#define VIEW_SPIDER 7
#define VIEW_MOKU 8

/**
 * variabel penyimpan ukuran dari jendela program, dimana
 * WIDTH ialah lebar jendela dan HEIGHT ialah tinggi jendela.
 */
GLfloat WINDOWS_HEIGHT = 420;
GLfloat WINDOWS_WIDTH  = 860;


static GLfloat theta[11] = {0.0, // sudut untuk pergerakan body
                            0.0, // sudut pergerakan kepala ke atas-bawah
                            0.0, // sudut pergerakan kepala ke kanan-kiri
                            -30.0, // sudut persambungan kaki depan kiri atas dengan body
                            120.0, // sudut persambungan kaki depan kiri bawah dengan atas
                            30.0,   // sudut persambungan kaki depan kanan atas dengan body
                            -120.0, // sudut persambungan kaki depan kanan bawah dengan atas
                            -30.0, // sudut persambungan kaki belakang kiri atas dengan body
                            120.0, // sudut persambungan kaki belakang kiri bawah dengan atas
                            30.0, // sudut persambungan kaki belakang kanan atas dengan body
                            -120.0 // sudut persambungan kaki belakang kanan bawah dengan atas
                           }; /* initial joint angles */


static GLfloat mokuAngle[13] = {
    0.0,    // bagian badan
    0.0,    // bagian kepala 1
    0.0,    // bagian kepala 2
    0.0,    // bagian tangan kiri bagian atas
    0.0,    // bagian tangan kiri bagian bawah
    0.0,    // bagian tangan kanan bagian atas
    0.0,    // bagian tangan kanan bagian bawah
    90.0,   // bagian tangan kanan bagian telapak
    -90.0,  // bagian roda 1
    90.0,   // bagian tangan kiri bagian telapak
    180.0,  // bagian roda 2
    0.0,    // bagian bawah 2
    0.0     // bagian bawah 1
};

int view = VIEW_ALL;

/**
 * variabel sudut dan perpindahan z dari Mokuton, untuk animasi
 * atau pergerakan mokuton.
 */
GLfloat mokutonAngle = 0.0;
GLfloat mokutonRot = 0.0;
GLfloat mokutonZ = 0.0;

static bool isTexture_s = false;
static bool isTexture_m = false;
static bool isAnimated = false;
static bool OBJECT_MODE = OBJECT_SHADING;
static bool mokuT = false;

/**
 * sudut yang sekarang dituju untuk dilakukan perubahan dinamis
 * saat jendela layar program sedang diam.
 */
static GLint s_angle = 0;
static GLint m_angle = 0;
static int angle = 0;
/**
 * variabel togle untuk keadaan :
 *  - up : kepala angguk (dua arah berlawanan)
 *  - isLightOn : nyala lampu
 *  - mokuTogle : arah gerakan Mokuton (dua arah berlawanan)
 */
bool up = true;
bool isLightOn = true;
bool mokuTogle = false;

/**
 * variabel pengatur dinamika pergerakan dari objek
 */
double inc = 2;
double light_angle = 0;

/**
 * posisi dinamis dari lampu yang bergerak secara dinamis
 */
float lamp_dynamic_pos[] = {10.0, 3.0, -29.0};
float lamp_dynamic_pos_ed[] = {10.0, 3.0, -29.0};

/**
 * definisi lampu dasar. dimana didefinisikan specular,
 * diffuse, ambient, dan posisinya
 */
GLfloat
light_ambient[]= {0.0, 0.0, 0.0, 1.0},
                         light_diffuse[]= {1.0, 1.0, 1.0, 1.0},
                                 light_specular[]= {1.0, 1.0, 1.0, 1.0},
                                         light_position[]= {0.0, 16.0, 19.0, 1.0};

/**
 * definisi lampu dinamis. dimana didefinisikan specular,
 * diffuse, ambient, dan posisinya
 */
GLfloat /*light 5: the rotating light */
lamp_dynamic_ambient[] = {0.0, 0.0, 0.0, 1.0},
                         lamp_dynamic_diffuse[] = {1.0, 0.0, 0.0, 0.0}, //RED
                                 lamp_dynamic_specular[] = {0.6, 0.6, 0.6, 1.0},
                                         lamp_dynamic_position[] = {-7.2, 3.0, -20.0, 1.0};
/**
 * definisi lampu satu. dimana didefinisikan specular,
 * diffuse, ambient, dan posisinya (berada pada dekat kamera atau di belakang)
 */
GLfloat /*light 1: the near static lamp */
lamp_one_ambient[] = {0.0, 0.0, 0.0, 1.0},
                         lamp_one_diffuse[] = {0.0, 1.0, 0.0, 0.0}, // GREEN
                                 lamp_one_specular[] = {0.6, 0.6, 0.6, 1.0},
                                         lamp_one_position[] = {-29.0, 16.0, 0.0, 1.0};

/**
 * definisi lampu dua. dimana didefinisikan specular,
 * diffuse, ambient, dan posisinya (berada pada samping kanan objek paling kanan)
 */
GLfloat /*light 2: the near static lamp */
lamp_two_ambient[] = {0.0, 0.0, 0.0, 1.0},
                         lamp_two_diffuse[] = {0.0, 0.0, 1.0, 0.0}, // BLUE
                                 lamp_two_specular[] = {0.6, 0.6, 0.6, 1.0},
                                         lamp_two_position[] = {49.0, 16.0, 0.0, 1.0};
/**
 * definisi material dari mat, dimana didefinisikan specular,
 * diffuse, ambient, dan shininess
 */
GLfloat
mat_specular[]= {1.0, 1.0, 1.0, 1.0},
                        mat_diffuse[]= {1.0, 1.0, 1.0, 1.0},
                                       mat_ambient[]= {1.0, 1.0, 1.0, 1.0},
                                               mat_shininess= {100.0};
/**
 * definisi material dari emas, dimana didefinisikan specular,
 * diffuse, ambient, dan shininess
 */
GLfloat /* gold material */
gold_ambient[] = {0.247, 0.1995, 0.0745},
                 gold_diffuse[] = {0.7516, 0.6065, 0.2265},
                                  gold_specular[] = {0.6283, 0.5558, 0.366},
                                          gold_shininess = 51.2;
/**
 * definisi material dari pewter, dimana didefinisikan specular,
 * diffuse, ambient, dan shininess
 */
GLfloat /* pewter material */
pewter_ambient[] = {0.105882, 0.058824, 0.113725, 1.0},
                   pewter_diffuse[] = {0.427451, 0.470588, 0.541176, 1.0},
                                      pewter_specular[] = {0.333333, 0.333333, 0.521569, 1.0},
                                              pewter_shininess = 9.85;
/**
 * definisi material dari mutiara, dimana didefinisikan specular,
 * diffuse, ambient, dan shininess
 */
GLfloat /*pearl material */
pearl_ambient[] = {0.25, 0.20725, 0.20725, 0.922},
                  pearl_diffuse[] = {1.0, 0.829, 0.829, 0.922},
                                    pearl_specular[] = {0.296648, 0.296648, 0.296648, 0.922},
                                            pearl_shininess = 11.26;

float floorNormal[] = {0.0, -1.0, 0.0}; // matrix used to calculate our projected floor shadow
float backNormal[] = {0.0, 0.0, -1.0};
float leftNormal[] = {-1.0, 0.0, 0.0};
float rightNormal[] = {1.0, 0.0, 0.0};

float backPointRot[] = {0.0, 0.0, -29.0};
float floorPointRot[] = {0.0, -9.9, -17.5};
float leftPointRot[] = {-29.0, 0.0, 0.0};
float rightPointRot[] = {49.0, 0.0, 0.0};

float backPoint1Rot[] = {0.0, 0.0, -19.0};  //lokasi bayangan pada dinding bagian belakang
float floorPoint1Rot[] = {0.0, -9.9, -17.5}; //lokasi bayangan pada lantai
float leftPoint1Rot[] = {-49.0, 0.0, 0.0};  //lokasi bayangan pada dinding bagian kiri
float rightPoint1Rot[] = {29.0, 0.0, 0.0};  //lokasi bayangan pada dinding bagian kanan

float lamp1_pos[] = {-7.2, 3.0, -20.0};
float lamp1_pos_rot[] = {-7.2, 3.0, -20.0};
float lamp2_pos[] = {-29.0, 16.0, 0.0};
float lamp3_pos[] = {0.0, 16.0, 19.0};
float lamp4_pos[] = {49.0, 16.0, 0.0};

float lamp1_pos1[] = {-7.2, 3.0, -20.0};
float lamp1_pos1_rot[] = {-7.2, 3.0, -20.0};
float lamp2_pos1[] = {-49, 16.0, 10.0};
float lamp3_pos1[] = {0.0, 16.0, 19.0};
float lamp4_pos1[] = {29.0, 16.0, 10.0};


GLuint texture[6];
static GLfloat slanted[] = {0.0, 1.0, 0.0, 1.0};
static float spot_direction[] = { 0., 1., 0., 1.};
bool isLight[] = {true, true, true, true};


float cameraPositionX = 10.0;
float cameraPositionY = 0.0;
float cameraPositionZ = 30.0;

float cameraLookX = 10.0;
float cameraLookY = 0.0;
float cameraLookZ = 0.0;


float cameraAngle = 0.0;

/**
 * memasukan definisi pada functions.h dan glutfunctions.h
 */

#include "menu.h"
#include "functions.h"
#include "glutfunctions.h"

/**
 * fungsi pengatur lampu pada enumerasi yang diberikan dengan posisi, ambient dinfusi serta spekular
 * dari lampu tersebut. dan dinyalakan.
 */
static void glSetLight(GLenum LIGHT_TYPE, GLfloat* pos, GLfloat* amb, GLfloat* diff, GLfloat* spec) {
    // atur lampu
    glLightfv(LIGHT_TYPE, GL_POSITION, pos);
    glLightfv(LIGHT_TYPE, GL_AMBIENT, amb);
    glLightfv(LIGHT_TYPE, GL_DIFFUSE, diff);
    glLightfv(LIGHT_TYPE, GL_SPECULAR, spec);
    // menyalakan
    glEnable(LIGHT_TYPE);
}


/**
 * inisialisasi material dan lampu yang digunakan dalam aplikasi ini
 */
void initMaterials() {



    // membisakan pencahayaan
    glEnable(GL_LIGHTING);
    // pengaturan lampu 0 sebagai lampu dasar
    glSetLight(GL_LIGHT0, light_position, light_ambient, light_diffuse, light_specular);
    // pengaturan lampu 5 sebagai lampu gerak
    glSetLight(GL_LIGHT5, lamp_dynamic_position, lamp_dynamic_ambient, lamp_dynamic_diffuse, lamp_dynamic_specular);
    // pengaturan lampu 1
    glSetLight(GL_LIGHT1, lamp_one_position, lamp_one_ambient, lamp_one_diffuse, lamp_one_specular);
    // pengaturan lampu 2
    glSetLight(GL_LIGHT2, lamp_two_position, lamp_two_ambient, lamp_two_diffuse, lamp_two_specular);

    // atur material awal
    glSetMaterial(mat_specular, mat_ambient, mat_ambient, mat_shininess);

    glShadeModel(GL_SMOOTH);
    glDepthFunc(GL_LEQUAL);
    glEnable(GL_DEPTH_TEST);

    char string[] = "texture1.raw";
    for(int i=0; i<6; i++) {
        string[7] = '1' + i;
        texture[i] = LoadTexture(string, 1);
        printf("nama file : %s\n", string);
         if (!texture[i]) printf("Texture File %d not found !\n", i);
    }
}

/**
 * pengturan awal untuk Glut, berhubungan dengan aturan jendela awal dari
 * GLUT. dimulai dari mode penggambaran, jumlah buffer, nama jendela atau
 * tipe pewarnaan atau yang lainnya.
 */
static void initGlutSettings(int argc, char *argv[]) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(WINDOWS_WIDTH, WINDOWS_HEIGHT);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable( GL_BLEND );
    glutInitWindowPosition(200,180);
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
    glutCreateWindow("Hierarchical Modelling Lighting, Shadow, and Texture, Worksheet 4 | Andry Luthfi, Hadi Saputro");
}

/**
 * inisialisasi fungsi pengendali atau callback dari suatu rutinitas
 * seperti rutinitas penggambaran atau saat terjadi perubahan ukuran
 * jendela. dan juga menginisialisasi fungsi yang mengendalikan
 * masukan dari mouse.
 */
static void initFunctionsHandler() {
    glutIdleFunc(functionIdle);
    glutReshapeFunc(functionReshape);
    glutDisplayFunc(functionDisplay);
    glutMouseFunc(handlerMouse);
    glutKeyboardFunc(handlerKeyboard);
    glutSpecialFunc(handlerSpecialKeyboard);
}

/**
 * inisialisasi pengaturan lainnya yang digunakan untuk program ini.
 * biasanya fungsi ini memanggil fungsi-fungsi inisialisasi lainnya.
 */
static void inits() {
    initMaterials();

    glClearColor(1.0, 1.0, 1.0, 1.0);
    glColor3f(0.0, 0.0, 0.0);

    initSpider();
    initMoku();
    init_table();
}

/**
 * inisialisasi menu, didefinisikan kemungkinan menu yang muncul dan
 * submenunya serta fungsi callback yang digunakan sebagai pengendali
 * saat menu tersebut dipanggil atau ditanggapi oleh pengguna.
 */
static void initMenu() {
    int body_menu, head_menu, head_menu2,
        left_upper_arm_menu, left_lower_arm_menu,
        right_upper_arm_menu, right_lower_arm_menu,
        texture_menu, object_mode;
    body_menu = glutCreateMenu(menu_body);
    create_submenu();
    head_menu = glutCreateMenu(menu_head);
    create_submenu();
    head_menu2 = glutCreateMenu(menu_head2);
    create_submenu();
    left_upper_arm_menu = glutCreateMenu(menu_left_upper_arm);
    create_submenu();
    left_lower_arm_menu = glutCreateMenu(menu_left_lower_arm);
    create_submenu();
    right_upper_arm_menu = glutCreateMenu(menu_right_upper_arm);
    create_submenu();
    right_lower_arm_menu = glutCreateMenu(menu_right_lower_arm);
    create_submenu();
    texture_menu = glutCreateMenu(menu_texture);
    create_submenu();
    object_mode = glutCreateMenu(menu_object);
    glutAddMenuEntry("Wireframe Mode", 0);
    glutAddMenuEntry("Shading Mode", 1);

    glutCreateMenu(handlerMenu);
    glutAddSubMenu("Move Body", body_menu);
    glutAddSubMenu("Move Head", head_menu);
    glutAddSubMenu("Move Head2", head_menu2);
    glutAddSubMenu("Move Left Upper Arm", left_upper_arm_menu);
    glutAddSubMenu("Move Left Lower Arm", left_lower_arm_menu);
    glutAddSubMenu("Move Right Upper Arm", right_upper_arm_menu);
    glutAddSubMenu("Move Right Lower Arm", right_lower_arm_menu);
    glutAddSubMenu("Texture", texture_menu);
    glutAddSubMenu("Object Mode", object_mode);
    glutAddMenuEntry("Animates",11);
    glutAddMenuEntry("Exit", 12);
    glutAttachMenu(GLUT_MIDDLE_BUTTON);
}
